using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using full_leaf_framework.Effect;
using full_leaf_framework.Visual;
using Microsoft.Xna.Framework;

namespace touhou_bullet_rain;

public class Level {

    private Dictionary<string, Player> players;
    private Dictionary<string, Projectile> projectiles;
    private Dictionary<string, Youkai> youkais;
    private Dictionary<string, Item> items;
    // 对局对象信息

    public float mapWidth = 100;
    public float mapHeight = 100;

    public bool autoStart = false;
    public float autoStartTime = 30.0f;
    public int autoStartMinPlayerCount = 1;

    public long mostRecentInteractTime = 0;
    public long mostRecentCallBackTime = 0;
    public long receiveTimeSpan = 0;
    public long latency = 0;

    public ParticleController particleController;

    public bool gameStarted = false;
    public float leftTime = 300.0f;

    public List<string> logs;
    const int logMaxCount = 10;

    public string serverName = "";
    public string[] serverInfo = new string[0];

    private LevelClient levelClient;

    public Dictionary<string, Player> Players { get => players; set => players = value; }
    public Dictionary<string, Projectile> Projectiles { get => projectiles; set => projectiles = value; }
    public Dictionary<string, Youkai> Youkais { get => youkais; set => youkais = value; }
    public Dictionary<string, Item> Items { get => items; set => items = value; }
    public LevelClient LevelClient { get => levelClient; set => levelClient = value; }

#region 初始化关卡信息

    public Level() {
        players = new Dictionary<string, Player>();
        projectiles = new Dictionary<string, Projectile>();
        youkais = new Dictionary<string, Youkai>();
        items = new Dictionary<string, Item>();
        logs = new List<string>();
        LevelClient = new LevelClient(this);
        particleController = new ParticleController("Effect/particles.json", GameManager.Content);
    }

    public async Task StartGame(string serverUri) {
        await LevelClient.StartRequestTask(serverUri);
        // levelClient将开启自己的线程
    }

#endregion

#region 更新关卡信息

    public void Update(GameTime gameTime) {
        lock (levelClient.bufferLock) {
            while (LevelClient.ActionsBuffer.Count > 0) {
                var interact = LevelClient.ActionsBuffer.Dequeue();
                interact.HandleLevelAction(this);
            }
            // 对缓冲区的所有动作作用到本地游戏
        }
        particleController.Update(gameTime);
        foreach (Player player in players.Values) {
            player.Update(gameTime);
        }
        foreach (Projectile projectile in projectiles.Values) {
            projectile.Update(gameTime);
        }
        foreach (Youkai youkai in youkais.Values) {
            youkai.Update(gameTime);
        }
        foreach (Item item in items.Values) {
            item.Update(gameTime);
        }
        if (logs.Count > logMaxCount) {
            logs.RemoveAt(0);
        }
        // 此处的更新作为本地更新，平滑填充服务器的同步帧
        autoStartTime -= (float)gameTime.ElapsedGameTime.TotalSeconds;
    }

    public void EndGame() {
        LevelClient.Disconnect();
    }

#endregion

#region 绘制关卡信息

    public void Draw(Camera camera) {
        foreach (Player player in players.Values) { player.Draw(camera); }
        foreach (Projectile projectile in projectiles.Values) { projectile.Draw(camera); }
        foreach (Youkai youkai in youkais.Values) { youkai.Draw(camera); }
        foreach (Item item in items.Values) { item.Draw(camera); }
        DrawMapEdge(camera);
        particleController.Draw(camera);
    }

    public void DrawMapEdge(Camera camera) {
        camera.DrawLine(GameManager.spriteBatch, new Vector2(-mapWidth / 2, -mapHeight / 2),
            new Vector2(-mapWidth / 2, mapHeight / 2), 2);
        camera.DrawLine(GameManager.spriteBatch, new Vector2(-mapWidth / 2, mapHeight / 2),
            new Vector2(mapWidth / 2, mapHeight / 2), 2);
        camera.DrawLine(GameManager.spriteBatch, new Vector2(mapWidth / 2, mapHeight / 2),
            new Vector2(mapWidth / 2, -mapHeight / 2), 2);
        camera.DrawLine(GameManager.spriteBatch, new Vector2(mapWidth / 2, -mapHeight / 2),
            new Vector2(-mapWidth / 2, -mapHeight / 2), 2);
    }

}

#endregion